
public class GameState {
	Board _board;
	int _4Count;
	int _3Count;
	int _2Count;
	int _1Count;
	GameStateEnum _GameStateEnum = GameStateEnum.PLAYER_1_TURN;
	
	GameState(Board board) {
		_board = board;
	}
	
	
	GameStateEnum alternatePlayerTurn() {
		if (_GameStateEnum == GameStateEnum.PLAYER_1_TURN) {
			_GameStateEnum = GameStateEnum.PLAYER_2_TURN;
		} else if (_GameStateEnum == GameStateEnum.PLAYER_2_TURN) {
			_GameStateEnum = GameStateEnum.PLAYER_1_TURN;
		}
		return _GameStateEnum;
	}
	
	boolean isPlayerTurn(GameStateEnum game_state) {
		if (game_state == GameStateEnum.PLAYER_1_TURN) {
			return true;
		} else if (game_state == GameStateEnum.PLAYER_2_TURN) {
			return true;
		} else {
			return false;
		}
	}
	
	boolean isWinningState(GameStateEnum game_state) {
		if (game_state == GameStateEnum.PLAYER_1_WIN) {
			return true;
		} else if (game_state == GameStateEnum.PLAYER_2_WIN) {
			return true;
		} else {
			return false;
		}
	}
	
	GameStateEnum evaluateBoardVeriticalWin() {
		Player player = Player.ONE;
		int total = 0;
		for (int c=0; c < _board._numColumns; ++c) {
			total = 0;
			player = _board._columns[c]._row[0].GetPlayer();
			if (player == Player.NONE) {
				continue;
			}
			total = 1;
			for (int r=1; r<_board._columns[c]._numPieces; ++r) {
				if (_board._columns[c]._row[r].GetPlayer() == Player.NONE) {
					break;
				} else if (_board._columns[c]._row[r].GetPlayer() == player) {
					++total;
					if (total == 4) {
						if (player == Player.ONE) {
							_GameStateEnum = GameStateEnum.PLAYER_1_WIN;
						} else {
							_GameStateEnum = GameStateEnum.PLAYER_2_WIN;
						}
					}
				} else {
					player = _board._columns[c]._row[r].GetPlayer();
				}
			}
		}
		return _GameStateEnum;
	}
	
	GameStateEnum evaluateBoardHorizontalWin() {
		Player player = Player.ONE;
		int total = 0;
		for (int r=0; r<_board._numRows; ++r) {
			player = _board._grid[0][r].GetPlayer();
			total = 1;
			for (int c=1; c<_board._numColumns; ++c) {
				if (_board._grid[c][r].GetPlayer() == Player.NONE) {
					total = 0;
				} else if (_board._grid[c][r].GetPlayer() == player) {
					++total;
					if (total == 4) {
						if (player == Player.ONE) {
							_GameStateEnum = GameStateEnum.PLAYER_1_WIN;
						} else {
							_GameStateEnum = GameStateEnum.PLAYER_2_WIN;
						}
					}
				}  else {
					player = _board._grid[c][r].GetPlayer();
					total = 1;
				}
			}
		}
		return _GameStateEnum;
	}
	
	GameStateEnum evaluateBoardWin() {
		// check for a horizontal win
		for (int row=0; row<_board._numRows; row++) {
			for (int column=0; column<_board._numColumns-3; column++) {
				Player player = _board._grid[column][row].GetPlayer();
				if (player == _board._grid[column+1][row].GetPlayer() &&
					player == _board._grid[column+2][row].GetPlayer() &&
					player == _board._grid[column+3][row].GetPlayer()) {
					if (player == Player.ONE) {
						_GameStateEnum = GameStateEnum.PLAYER_1_WIN;
					} else if (player == Player.TWO) {
						_GameStateEnum = GameStateEnum.PLAYER_2_WIN;
					} else {
						continue;
					}
					return _GameStateEnum;
				}
			}
		}
		
		// check for a vertical win
		for (int row=0; row<_board._numRows-3; row++) {
			for (int column=0; column<_board._numColumns; column++) {
				Player player = _board._grid[column][row].GetPlayer();
				if (player == _board._grid[column][row+1].GetPlayer() &&
					player == _board._grid[column][row+2].GetPlayer() &&
					player == _board._grid[column][row+3].GetPlayer()) {
					if (player == Player.ONE) {
						_GameStateEnum = GameStateEnum.PLAYER_1_WIN;
					} else if (player == Player.TWO) {
						_GameStateEnum = GameStateEnum.PLAYER_2_WIN;
					} else {
						continue;
					}
					return _GameStateEnum;
				}
			}
		}
		
		// check for a diagonal win (positive slope)
		for (int row=0; row<_board._numRows-3; row++) {
			for (int column=0; column<_board._numColumns-3; column++) {
				Player player = _board._grid[column][row].GetPlayer();
				if (player == _board._grid[column+1][row+1].GetPlayer() &&
					player == _board._grid[column+2][row+2].GetPlayer() &&
					player == _board._grid[column+3][row+3].GetPlayer()) {
					if (player == Player.ONE) {
						_GameStateEnum = GameStateEnum.PLAYER_1_WIN;
					} else if (player == Player.TWO) {
						_GameStateEnum = GameStateEnum.PLAYER_2_WIN;
					} else {
						continue;
					}
					return _GameStateEnum;
				}
			}
		}
		
		// check for a diagonal win (negative slope)
		for (int row=3; row<6; row++) {
			for (int column=0; column<_board._numColumns-3; column++) {
				Player player = _board._grid[column][row].GetPlayer();
				if (player == _board._grid[column+1][row-1].GetPlayer() &&
					player == _board._grid[column+2][row-2].GetPlayer() &&
					player == _board._grid[column+3][row-3].GetPlayer()) {
					if (player == Player.ONE) {
						_GameStateEnum = GameStateEnum.PLAYER_1_WIN;
					} else if (player == Player.TWO) {
						_GameStateEnum = GameStateEnum.PLAYER_2_WIN;
					} else {
						continue;
					}
					return _GameStateEnum;
				}
			}
		}
		return _GameStateEnum;
	}
	
	
	
	///////////////////////////////////////////////////////////////////////////////
	///////////////////////// PLACED WIN //////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////
	
	boolean checkPlacedPiece(Tile placedTile, Player player, int total) {
		if (placedTile != null) {
			if (placedTile.GetPlayer() == player) {
				if (total >= 4) {
					if (player == Player.ONE) {
						_GameStateEnum = GameStateEnum.PLAYER_1_WIN;
					} else {
						_GameStateEnum = GameStateEnum.PLAYER_2_WIN;
					}
					return false;
				}
				return true;
			}
		}
		return false;
	}
	
	int evaluateBoardPlacedVerticalWin(Tile placedTile) {
		Player player = placedTile.GetPlayer();
		int total = 1;
		for (int i=0; i<3; ++i) {
			placedTile = placedTile._bottom;
			if (!checkPlacedPiece(placedTile, player, ++total)) break;
		}
		
		if (total == 4) {
			if (isWinningState(_GameStateEnum))
				return 4;
		}
		
		return total-1;
	}
	
	int evaluateBoardPlacedHorizontalWin(Tile placedTile) {
		Player player = placedTile.GetPlayer();
		int total = 1;
		Tile temp = placedTile;
		for (int i=0; i<3; ++i) {
			placedTile = placedTile._left;
			if (checkPlacedPiece(placedTile, player, total+1)) {
				++total;
				continue;
			}
			break;
		}
		
		if (isWinningState(_GameStateEnum)) return 4;
		
		for (int i=0; i<3; ++i) {
			temp = temp._right;
			if (!checkPlacedPiece(temp, player, ++total)) break;
		}
		
		if (total == 4) {
			if (isWinningState(_GameStateEnum))
				return 4;
		}
		
		return total-1;
	}
	
	int evaluateBoardPlacedDiagonalPosSlopedWin(Tile placedTile) {
		Player player = placedTile.GetPlayer();
		int total = 1;
		Tile temp = placedTile;
		for (int i=0; i<3; ++i) {
			placedTile = placedTile._left;
			if (placedTile != null) {
				placedTile = placedTile._top;
				if (checkPlacedPiece(placedTile, player, total+1)) {
					++total;
					continue;
				}
			}
			break;
		}
		
		if (isWinningState(_GameStateEnum)) return 4;
		
		placedTile = temp;
		for (int i=0; i<3; ++i) {
			placedTile = placedTile._right;
			if (placedTile != null) {
				placedTile = placedTile._bottom;
				if (checkPlacedPiece(placedTile, player, ++total)) continue;
			}
			break;
		}
		
		if (total == 4) {
			if (isWinningState(_GameStateEnum))
				return 4;
		}
		
		return total-1;
	}
	
	int evaluateBoardPlacedDiagonalNegSlopedWin(Tile placedTile) {
		Player player = placedTile.GetPlayer();
		int total = 1;
		Tile temp = placedTile;
		for (int i=0; i<3; ++i) {
			placedTile = placedTile._left;
			if (placedTile != null) {
				placedTile = placedTile._bottom;
				if (checkPlacedPiece(placedTile, player, total+1)) {
					++total;
					continue;
				}
			}
			break;
		}
		
		if (isWinningState(_GameStateEnum)) return 4;
		
		placedTile = temp;
		for (int i=0; i<3; ++i) {
			placedTile = placedTile._right;
			if (placedTile != null) {
				placedTile = placedTile._top;
				if (checkPlacedPiece(placedTile, player, ++total)) continue;
			}
			break;
		}
		
		if (total == 4) {
			if (isWinningState(_GameStateEnum))
				return 4;
		}
		
		return total-1;
	}
	
	void generateCounts(Player player) {
		_1Count = 0;
		_2Count = 0;
		_3Count = 0;
		_4Count = 0;
		
		generateHorizontalCounts(player);
		generateVerticalCounts(player);
		generateDiagonalPosSlopeCounts(player);
	}
	
	void generateHorizontalCounts(Player player) {
		int count = 0;
		
		for (int row=0; row<_board._numRows; row++) {
			Tile temp = _board._grid[0][row];
			Tile temp2 = null;
			for (int i=0; i<6; ++i) {
				if (temp != null) {
					if (temp.GetPlayer() == player) {
						++count;
						temp = temp._right;
						continue;
					}
				}
				
				checkCounts(temp, temp2, count);
				count = 0;
				temp2 = temp;
				if (temp != null) {
					temp = temp._right;
				}
				
			}
		}
	}
	
	void generateVerticalCounts(Player player) {
		int count = 0;
		
		for (int col=0; col<_board._numColumns; col++) {
			Tile temp = _board._grid[col][0];
			Tile temp2 = null;
			for (int i=0; i<6; ++i) {
				if (temp != null) {
					if (temp.GetPlayer() == player) {
						++count;
						temp = temp._top;
						continue;
					}
				}
				
				checkCounts(temp, temp2, count);
				
				count = 0;
				temp2 = temp;
				if (temp != null) {
					temp = temp._top;
				}
				
			}
		}
	}
	
	void generateDiagonalPosSlopeCounts(Player player) {
		int count = 0;
		
		for (int col=0; col<_board._numColumns; col++) {
			Tile temp = _board._grid[col][0];
			Tile temp2 = null;
			for (int i=0; i<6; ++i) {
				if (temp != null) {
					if (temp.GetPlayer() == player) {
						++count;
						temp = temp._top;
						continue;
					}
				}
				
				checkCounts(temp, temp2, count);
				
				count = 0;
				temp2 = temp;
				if (temp != null) {
					temp = temp._top;
					if (temp != null) {
						temp = temp._right;
					}
				}
				
			}
		}
		for (int row=1; row<_board._numRows; row++) {
			Tile temp = _board._grid[0][row];
			Tile temp2 = null;
			for (int i=0; i<6; ++i) {
				if (temp != null) {
					if (temp.GetPlayer() == player) {
						++count;
						temp = temp._top;
						continue;
					}
				}
				
				checkCounts(temp, temp2, count);
				
				count = 0;
				temp2 = temp;
				if (temp != null) {
					temp = temp._top;
					if (temp != null) {
						temp = temp._right;
					}
				}
				
			}
		}
	}
	
	
	void checkCounts(Tile temp, Tile temp2, int count) {
		if (count != 0) {
			if (temp == null) {
				switch (count) {
					case 1: ++_1Count; break;
					case 2:	++_2Count; break;
					case 3:	++_3Count; break;
					case 4: ++_4Count; break;
				}
			} else if (temp2 == null) {
				if (temp.GetPlayer() == Player.NONE) {
					switch (count) {
						case 1: ++_1Count; break;
						case 2:	++_2Count; break;
						case 3:	++_3Count; break;
						case 4: ++_4Count; break;
					}
				}
			} else if (temp.GetPlayer() == Player.NONE || temp2.GetPlayer() == Player.NONE) {
				switch (count) {
					case 1: ++_1Count; break;
					case 2:	++_2Count; break;
					case 3:	++_3Count; break;
					case 4: ++_4Count; break;
				}
			}
		}
	}
	
	GameStateEnum evaluateBoardPlacedPieceWin(Tile placedPiece) {
		if (evaluateBoardPlacedVerticalWin(placedPiece) != 4) {
			if (evaluateBoardPlacedHorizontalWin(placedPiece) != 4) {
				if (evaluateBoardPlacedDiagonalNegSlopedWin(placedPiece) != 4) {
					evaluateBoardPlacedDiagonalPosSlopedWin(placedPiece);					
				}
			}
		}
		return _GameStateEnum;
	}

	
}
